package com.googlecode.pacswitch.actions;

import java.nio.channels.AsynchronousSocketChannel;
import java.util.List;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import com.googlecode.pacswitch.ObjectFactory;
import com.googlecode.pacswitch.PacSwitch;
import com.googlecode.pacswitch.Property;
import com.googlecode.pacswitch.PropertyValue;

/**
 * @author Andrey Pavlenko
 */
@XmlType(name = "BestProxy", namespace = ObjectFactory.ANS)
public class BestProxy extends Pac implements PropertyValue {
    private String _proxies;
    private Proxies _nestedProxies;

    @XmlAttribute
    public String getProxies() {
        return _proxies;
    }

    public void setProxies(final String proxies) {
        _proxies = proxies;
    }

    @Override
    @XmlElement(name = "header", type = Header.class,
        namespace = ObjectFactory.ANS)
    public List<Header> getHeaders() {
        return super.getHeaders();
    }

    @XmlTransient
    public Proxies getNestedProxies() {
        return _nestedProxies;
    }

    public Proxies getNestedProxiesAction() {
        return _nestedProxies;
    }

    @XmlElement(name = "proxies", type = Proxies.class,
        namespace = ObjectFactory.ANS, required = false)
    public void setNestedProxiesAction(final Proxies nestedProxies) {
        _nestedProxies = nestedProxies;
    }

    public Proxies getNestedProxiesProperty() {
        return _nestedProxies;
    }

    @XmlElement(name = "proxies", type = Proxies.class,
        namespace = ObjectFactory.PNS, required = false)
    public void setNestedProxiesProperty(final Proxies nestedProxies) {
        _nestedProxies = nestedProxies;
    }

    @Override
    public String resolve(final PacSwitch ps,
            final AsynchronousSocketChannel clientSocket) {
        final Proxies proxies = getProxies(ps);

        if (proxies != null) {
            final List<Proxy> list = proxies.getSortedProxies(ps, clientSocket);

            if (!list.isEmpty()) {
                return list.get(0).resolve(ps, clientSocket);
            }
        }

        return "";
    }

    private Proxies getProxies(final PacSwitch ps) {
        final String propName = getProxies();

        if (propName != null) {
            final Property p = ps.getConfig().getProperty(propName);

            if (p == null) {
                ps.getConfig().getLog()
                        .warn("Property " + propName + " not found");
                return null;
            } else {
                final JAXBElement<PropertyValue> nested = p.getNestedValue();

                if (nested != null) {
                    final PropertyValue v = nested.getValue();

                    if (v instanceof Proxies) {
                        return (Proxies) v;
                    }
                }

                ps.getConfig()
                        .getLog()
                        .warn("Property " + propName
                                + " does not have nested element of type "
                                + Proxies.class.getName());
                return null;
            }
        }

        final Proxies nested = getNestedProxies();

        if (nested != null) {
            return nested;
        } else {
            ps.getConfig()
                    .getLog()
                    .warn("Either attribute 'proxies' or nested element of type "
                            + Proxies.class.getName() + " must be specified");
            return null;
        }
    }

    @Override
    protected String resolveBody(final PacSwitch ps,
            final AsynchronousSocketChannel clientSocket) {
        return Proxy.body("PROXY " + resolve(ps, clientSocket));
    }
}
